#include <dspSimulator/targetMachine/interruptHandle.h>


std::vector<InterruptKind> InterruptHandle::getActiveInterrupt() const {
    std::vector<InterruptKind> activeInterrupts;
    auto IFR = *m_dspMachine->getRegisters()->getReg32ByName("IFR")->getDataPtr();
    std::bitset<32> IFRBits = IFR;
    for (u32 i = 1; i <= 15; ++i) {
        if (IFRBits[i] == 1) {
            switch (i) {
                case 1:
                    activeInterrupts.push_back(InterruptKind::NMI);
                    break;
                case 4:
                    activeInterrupts.push_back(InterruptKind::INT4);
                    break;
                case 5:
                    activeInterrupts.push_back(InterruptKind::INT5);
                    break;
                case 6:
                    activeInterrupts.push_back(InterruptKind::INT6);
                    break;
                case 7:
                    activeInterrupts.push_back(InterruptKind::INT7);
                    break;
                case 8:
                    activeInterrupts.push_back(InterruptKind::INT9);
                    break;
                case 9:
                    activeInterrupts.push_back(InterruptKind::INT6);
                    break;
                case 10:
                    activeInterrupts.push_back(InterruptKind::INT10);
                    break;
                case 11:
                    activeInterrupts.push_back(InterruptKind::INT11);
                    break;
                case 12:
                    activeInterrupts.push_back(InterruptKind::INT12);
                    break;
                case 13:
                    activeInterrupts.push_back(InterruptKind::INT13);
                    break;
                case 14:
                    activeInterrupts.push_back(InterruptKind::INT14);
                    break;
                case 15:
                    activeInterrupts.push_back(InterruptKind::INT15);
                    break;
                default:
                    break;
            }
        }
    }
    return activeInterrupts;
}

std::vector<InterruptKind> InterruptHandle::getEnableInterrupt() const {
    std::vector<InterruptKind> enableInterrupts;
    enableInterrupts.push_back(InterruptKind::Reset);
    auto IFR = *m_dspMachine->getRegisters()->getReg32ByName("IFR")->getDataPtr();
    std::bitset<32> IFRBits = IFR;
    bool GIE = isEnableGlobalInterrupt();
    for (u32 i = 1; i <= 15; ++i) {
        if (IFRBits[i] == 1) {
            switch (i) {
                case 1:
                    enableInterrupts.push_back(InterruptKind::NMI);
                    break;
                case 4:
                    if (GIE)
                        enableInterrupts.push_back(InterruptKind::INT4);
                    break;
                case 5:
                    if (GIE)
                        enableInterrupts.push_back(InterruptKind::INT5);
                    break;
                case 6:
                    if (GIE)
                        enableInterrupts.push_back(InterruptKind::INT6);
                    break;
                case 7:
                    if (GIE)
                        enableInterrupts.push_back(InterruptKind::INT7);
                    break;
                case 8:
                    if (GIE)
                        enableInterrupts.push_back(InterruptKind::INT9);
                    break;
                case 9:
                    if (GIE)
                        enableInterrupts.push_back(InterruptKind::INT6);
                    break;
                case 10:
                    if (GIE)
                        enableInterrupts.push_back(InterruptKind::INT10);
                    break;
                case 11:
                    if (GIE)
                        enableInterrupts.push_back(InterruptKind::INT11);
                    break;
                case 12:
                    if (GIE)
                        enableInterrupts.push_back(InterruptKind::INT12);
                    break;
                case 13:
                    if (GIE)
                        enableInterrupts.push_back(InterruptKind::INT13);
                    break;
                case 14:
                    if (GIE)
                        enableInterrupts.push_back(InterruptKind::INT14);
                    break;
                case 15:
                    if (GIE)
                        enableInterrupts.push_back(InterruptKind::INT15);
                    break;
                default:
                    break;
            }
        }
    }

    return enableInterrupts;
}

bool InterruptHandle::isEnableGlobalInterrupt() const {
    auto CSR = *m_dspMachine->getRegisters()->getReg32ByName("CSR")->getDataPtr();
    std::bitset<32> CSRBits = CSR;
    if (CSRBits[0] == 1) {
        return true;
    } else {
        return false;
    }
}

void InterruptHandle::updateHPEINT(InterruptKind interruptKind) const {
    auto ISTPReg = m_dspMachine->getRegisters()->getReg32ByName("ISTP");
    // clear bit 5 to 9
    ISTPReg->updateData(*ISTPReg->getDataPtr() & 0xfffffc00);
    // update bit 5 to 9
    u32 interruptOffset = static_cast<u32>(interruptKind);
    interruptOffset <<= 5;
    ISTPReg->updateData(*ISTPReg->getDataPtr() | interruptOffset);
}

std::vector<InterruptKind> InterruptHandle::getClearFlags() const {
    std::vector<InterruptKind> clearFlags;
    auto ICR = *m_dspMachine->getRegisters()->getReg32ByName("ICR")->getDataPtr();
    std::bitset<32> ICRBits = ICR;
    for (u32 i = 4; i <= 15; ++i) {
        if (ICRBits[i] == 1) {
            switch (i) {
                case 4:
                    clearFlags.push_back(InterruptKind::INT4);
                    break;
                case 5:
                    clearFlags.push_back(InterruptKind::INT5);
                    break;
                case 6:
                    clearFlags.push_back(InterruptKind::INT6);
                    break;
                case 7:
                    clearFlags.push_back(InterruptKind::INT7);
                    break;
                case 8:
                    clearFlags.push_back(InterruptKind::INT9);
                    break;
                case 9:
                    clearFlags.push_back(InterruptKind::INT6);
                    break;
                case 10:
                    clearFlags.push_back(InterruptKind::INT10);
                    break;
                case 11:
                    clearFlags.push_back(InterruptKind::INT11);
                    break;
                case 12:
                    clearFlags.push_back(InterruptKind::INT12);
                    break;
                case 13:
                    clearFlags.push_back(InterruptKind::INT13);
                    break;
                case 14:
                    clearFlags.push_back(InterruptKind::INT14);
                    break;
                case 15:
                    clearFlags.push_back(InterruptKind::INT15);
                    break;
            }
        }
    }
    return clearFlags;
}

std::vector<InterruptKind> InterruptHandle::getSetFlags() const {
    std::vector<InterruptKind> setFlags;
    auto ISR = *m_dspMachine->getRegisters()->getReg32ByName("ISR")->getDataPtr();
    std::bitset<32> ICRBits = ISR;
    for (u32 i = 4; i <= 15; ++i) {
        if (ICRBits[i] == 1) {
            switch (i) {
                case 4:
                    setFlags.push_back(InterruptKind::INT4);
                    break;
                case 5:
                    setFlags.push_back(InterruptKind::INT5);
                    break;
                case 6:
                    setFlags.push_back(InterruptKind::INT6);
                    break;
                case 7:
                    setFlags.push_back(InterruptKind::INT7);
                    break;
                case 8:
                    setFlags.push_back(InterruptKind::INT9);
                    break;
                case 9:
                    setFlags.push_back(InterruptKind::INT6);
                    break;
                case 10:
                    setFlags.push_back(InterruptKind::INT10);
                    break;
                case 11:
                    setFlags.push_back(InterruptKind::INT11);
                    break;
                case 12:
                    setFlags.push_back(InterruptKind::INT12);
                    break;
                case 13:
                    setFlags.push_back(InterruptKind::INT13);
                    break;
                case 14:
                    setFlags.push_back(InterruptKind::INT14);
                    break;
                case 15:
                    setFlags.push_back(InterruptKind::INT15);
                    break;
            }
        }
    }
    return setFlags;
}

u32 InterruptHandle::getStartAddressOfIST() const {
    auto ISTP = *m_dspMachine->getRegisters()->getReg32ByName("ISTP")->getDataPtr();
    return ISTP;
}

void InterruptHandle::clearInterruptEnable(InterruptKind kind) const {
    u32 interruptOffset = static_cast<u32>(kind);
    auto IERReg = m_dspMachine->getRegisters()->getReg32ByName("IER");
    std::bitset<32> IERBits = *IERReg->getDataPtr();
    if (interruptOffset == 0 || interruptOffset == 2 || interruptOffset == 3) {
        return;
    }

    IERBits[interruptOffset] = 0;
    IERReg->updateData(IERBits.to_ulong());
}

void InterruptHandle::clearInterruptState(InterruptKind kind) const {
    u32 interruptOffset = static_cast<u32>(kind);
    auto IFRReg = m_dspMachine->getRegisters()->getReg32ByName("IFR");
    std::bitset<32> IFRBits = *IFRReg->getDataPtr();
    if (interruptOffset == 0 || interruptOffset == 2 || interruptOffset == 3) {
        return;
    }

    IFRBits[interruptOffset] = 0;
    IFRReg->updateData(IFRBits.to_ulong());
}

bool InterruptHandle::handleInterrupt() {
    // 获取所有的未被屏蔽的中断，如果没有，返回false
    auto activeInterrupts = getActiveInterrupt();
    auto enableInterrupts = getEnableInterrupt();

    // 获取优先级最高的中断
    InterruptKind interrupt;
    bool isFind = false;
    for (auto &activeInterrupt: activeInterrupts) {
        for (auto &enableInterrupt: enableInterrupts) {
            if (activeInterrupt == enableInterrupt) {
                isFind = true;
                interrupt = activeInterrupt;
                break;
            }
        }
        if (isFind) {
            break;
        }
    }

    if (!isFind) {
        return false;
    }

    // 保存任务状态寄存器TSR
    auto TSR = *m_dspMachine->getRegisters()->getReg32ByName("TSR")->getDataPtr();
    if (interrupt == InterruptKind::Reset) {

    } else if (interrupt == InterruptKind::NMI) {
        m_dspMachine->getRegisters()->getReg32ByName("NSTR")->updateData(TSR);
    } else {
        m_dspMachine->getRegisters()->getReg32ByName("ISTR")->updateData(TSR);
    }

    // 保存程序的返回地址
    auto pc = *m_dspMachine->getRegisters()->getReg32ByName("pc")->getDataPtr();
    if (interrupt == InterruptKind::Reset) {
        // do nothing
    } else if (interrupt == InterruptKind::NMI) {
        m_dspMachine->getRegisters()->getReg32ByName("NRP")->updateData(pc);
    } else {
        m_dspMachine->getRegisters()->getReg32ByName("IRP")->updateData(pc);
    }

    // 更新ISPT的HPEINT字段，数值为最高优先级的中断
    updateHPEINT(interrupt);

    // 获取需要处理的中断服务程序的首地址
    u32 baseAddress = getStartAddressOfIST();

    // 设置pc寄存器值为需要处理的中断服务程序的首地址
    m_dspMachine->getRegisters()->getReg32ByName("pc")->updateData(baseAddress);

    // 清除对应的中断允许位
    clearInterruptEnable(interrupt);

    // 当前中断状态位置0
    clearInterruptState(interrupt);

    // 执行中断处理函数
    return true;
}